/**
 * 
 */
package com.ms.service.module.zone.module;

import java.util.ArrayList;
import java.util.HashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ms.game.bank.BankProcessor;
import com.ms.game.characterInfo.CharacterInfoAction;
import com.ms.game.gmtool.ServerShutdownType;
import com.ms.game.gmtool.message.SGmtoolKickAllConnectionNotify;
import com.ms.game.gmtool.message.SGmtoolServerShutdownCountdownNotify;
import com.ms.game.gmtool.message.SGmtoolServerShutdownCountdownNotifyToClient;
import com.ms.game.purchase.action.PurchaseAction;
import com.ms.game.slot.base.SlotGameBasicAction;
import com.ms.player.Player;
import com.ms.service.module.account.message.SCharacterLoginNotify;
import com.ms.service.module.zone.BasicZone;
import com.ms.service.module.zone.UpdateTaskTimer;
import com.ms.service.module.zone.action.BasicZoneAction;
import com.ms.service.module.zone.action.DebugCommandAction;
import com.ms.service.module.zone.action.LoginZoneAction;
import com.ms.service.module.zone.action.SwitchZoneAction;
import com.ms.service.module.zone.action.ZoneVerifyAction;
import com.ms.service.telnet.STelnetCmd;
import com.xpec.c4.game.utility.GUID;
import com.xpec.c4.game.utility.GameUtility;
import com.xpec.c4.game.zone.PlayerDataAgentZone;
import com.xpec.c4.message.MessageTypes;
import com.xpec.c4.service.h5server.H5ServerOperations;
import com.xpec.c4.service.message.MessageAction;
import com.xpec.c4.service.module.BasicServiceModule;
import com.xpec.c4.service.module.ModuleName;
import com.xpec.c4.service.module.ServerProperties;
import com.xpec.c4.service.module.common.PlayerCommonInfoManager;
import com.xpec.c4.service.module.task.TaskTimer;
import com.xpec.c4.service.server.CloseType;
import com.xpec.c4.service.server.ServerOperations;

/**
 * 給遊戲館使用的基本 zone 模組
 * <p>
 * 使用方式：
 * <ul>
 * <li>繼承 BasicZoneModule 寫一個新的 module class 負責接收消息
 * <li>繼承 BasicZone 寫一個新的 zone class 負責管理遊戲館自己的邏輯和資料
 * <li>在 module 的 constructor 裡面把新的 zone class 實體指定給 BasicZoneModule.zone 這樣新的
 * zone class 就可以接收到 zone 的一些事件。
 * <li>視情況改寫父 class 裡面的一些 function
 * </ul>
 * 
 * @author TW15010
 */
public class BasicZoneModule extends BasicServiceModule {
	@SuppressWarnings("unused")
	private static final Log log = LogFactory.getLog(BasicZoneModule.class);

	/** 管理bank money call back */
	private BankProcessor bank = new BankProcessor();
	
	/**
	 * 玩家管理
	 */
	protected PlayerDataAgentZone playerDataAgent = new PlayerDataAgentZone(
			this);

	/** 更新事件觸發時間間隔 */
	public static final long UPDATE_PERIOD = 250;

	/** 管理 zone 的基礎資料 */
	private BasicZone zone = null;

	/** 取玩家資料用的 data agent */
	private PlayerDataAgentZone playerDataAgentZone = new PlayerDataAgentZone(
			this);

	/** update 事件最後觸發時間 */
	private long lastUpdateTime;

	@Override
	public void init() {
		super.init();
		zone.setZoneId(this.getModuleName());
		zone.setOwnerModule(this);
		
		//對應到的processer
		this.setBasicprocesser(zone);
		
		registerActionClass(LoginZoneAction.class);
		registerActionClass(ZoneVerifyAction.class);
		registerActionClass(SwitchZoneAction.class);
		registerActionClass(BasicZoneAction.class);
		registerActionClass(CharacterInfoAction.class);
		registerActionClass(DebugCommandAction.class);
		registerActionClass(PurchaseAction.class);
		
		registerActionClass(SlotGameBasicAction.class);
		
	}

	@Override
	public boolean startup() {
		// 設定 Zone update 計時器
		UpdateTaskTimer upd = new UpdateTaskTimer();

		upd.setTimerOption(TaskTimer.LOOP);
		upd.setInitialDelay(0);
		upd.setPeriod(UPDATE_PERIOD);
		upd.setCallback(this);
		addTaskTimer(upd);

		// 執行 zone 的啟動事件
		zone.onStartup();

		return super.startup();
	}

	/**
	 * UpdateTaskTimer 觸發
	 * 
	 * @param periodTime
	 */
	public void onUpdateTaskTimer(long periodTime) {
		// 計算距離上次觸發所經過的時間
		long cur = System.currentTimeMillis();
		long difftime = cur - lastUpdateTime;

		zone.onUpdate(difftime);

		this.lastUpdateTime = cur;
	}

	@Override
	public void shutdown() {
		super.shutdown();
	}

	@Override
	public void procTelnetCommand(STelnetCmd obj) {
	}

	public BasicZone getZone() {
		return zone;
	}

	public void setZone(BasicZone zone) {
		this.zone = zone;
	}

	public PlayerDataAgentZone getPlayerDataAgent() {
		return playerDataAgent;
	}

	public PlayerDataAgentZone getPlayerDataAgentZone() {
		return playerDataAgentZone;
	}

	@Override
	public void procThrowException(Object obj) {
		
	}
	
	public BankProcessor getBank() {
		return bank;
	}
	
	@Override
	public void onPlayerLoginGameNotify(SCharacterLoginNotify notify) {
		super.onPlayerLoginGameNotify(notify);
		getZone().onPlayerLoginGameNotify(notify);
	}
	
	/**
	 * 覆寫倒數計時，只有單一遊戲維護會走這
	 */
	@Override
	public void onRecvServerShutdownCountdownNotify(SGmtoolServerShutdownCountdownNotify notify) {
		super.onRecvServerShutdownCountdownNotify(notify);

		if (notify.getShutdownType() != ServerShutdownType.Single_Game) { // 基本上，單一機台維護才會走這邊
			return;
		}

		if (zone == null) {
			return;
		}

		HashMap<GUID, Player> playerList = zone.getPlayerList();
		if (GameUtility.getMapSize(playerList) <= 0) {
			return;
		}

		SGmtoolServerShutdownCountdownNotifyToClient toClientNotify = new SGmtoolServerShutdownCountdownNotifyToClient();
		toClientNotify.setCountdownTime(notify.getCountdownTime());
		toClientNotify.setCountdownType(notify.getShutdownType().getId());
		
		//收集要廣播的sessionID
		ArrayList<GUID> sendSessionIds = new ArrayList<GUID>();
		for (GUID guid : playerList.keySet()) {
			// 看看這個玩家是否還在這裡
			String zoneId = PlayerCommonInfoManager.getInstance().getZoneIdByPlayerId(guid);
			if (!GameUtility.isHaveString(zoneId) || !zoneId.equals(getModuleName())) { // 不在遊戲內，不管他
				continue;
			}

			GUID sessionId = PlayerCommonInfoManager.getInstance().getSessionByPlayerGuid(guid);
			if(sessionId == null){
				continue;
			}
			sendSessionIds.add(sessionId);
		}
		
		//收集完後一次廣播
		MessageAction.sendMessage(sendSessionIds, MessageTypes.S_GMTOOL_SERVER_SHUTDOWN_COUNTDOWN_NOTIFY_TO_CLIENT, toClientNotify);
	}
	

	/**
	 * 覆寫踢人，只有單一遊戲維護會走這
	 */
	@Override
	public void onRecvKickAllConnectionNotify(SGmtoolKickAllConnectionNotify request) {
		super.onRecvKickAllConnectionNotify(request);

		if (request.getShutdownType() != ServerShutdownType.Single_Game) { // 基本上，單一機台維護才會走這邊
			return;
		}

		if (zone == null) {
			return;
		}

		HashMap<GUID, Player> playerList = zone.getPlayerList();
		if (GameUtility.getMapSize(playerList) <= 0) {
			return;
		}

		for (GUID guid : playerList.keySet()) {
			// 從common看看這個玩家是否還在這裡
			String zoneId = PlayerCommonInfoManager.getInstance().getZoneIdByPlayerId(guid);
			if (!GameUtility.isHaveString(zoneId) || !zoneId.equals(getModuleName())) { // 不在遊戲內，不管他
				continue;
			}

			GUID sessionId = PlayerCommonInfoManager.getInstance().getSessionByPlayerGuid(guid);
			if(sessionId == null){
				continue;
			}
			
			if (ServerProperties.isTargetModule(PlayerCommonInfoManager.getInstance().getGatewayBySessionId(sessionId), ModuleName.H5GATEWAY)) {
				H5ServerOperations.sessionClose(sessionId, CloseType.KICK_BY_SERVER_SINGLE_MAINTAIN, this);
			} else {
				ServerOperations.sessionClose(sessionId, CloseType.KICK_BY_SERVER_SINGLE_MAINTAIN, this);
			}
		}
	}
}
